﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CrusadeGmTool.Net;
using CrusadeGmTool.Diagnostics;
using CrusadeGmTool.Net.IO;
using System.Threading;
using System.Windows.Forms;

namespace CrusadeGmTool.Models
{
    delegate void ConnectedEventhandler(object sender, bool connected);

    public enum LoginResponse : byte
    {
        NoUser = 0,
        BadIP,
        BadPass,
        NoAccess,
        OK
    }

    class Server
    {
        NetworkContext _network;
        Logger _log;
        string _adress;
        int _port;
        string _username;
        string _password;
        ServerInfo _serverInfo;

        public ServerInfo ServerInfo
        {
            get { return _serverInfo; }
            set { _serverInfo = value; }
        }
        System.Threading.Timer _requestInfoTimer;
        #region properties
        public NetworkContext Network
        {
            get { return _network; }
            set { _network = value; }
        }
        public string Adress
        {
            get { return _adress; }
            set { _adress = value; }
        }
        public int Port
        {
            get { return _port; }
            set { _port = value; }
        }
        public string Username
        {
            get { return _username; }
            set { _username = value; }
        }
        public string Password
        {
            get { return _password; }
            set { _password = value; }
        }
        #endregion

        /// <summary>
        /// Fired when connected to a server.
        /// </summary>
        public event ConnectedEventhandler connected;
        public event EventHandler UpdatedServerInfo;
        public Server()
        {
            _network = new NetworkContext();
            _log = new Logger(this.GetType());
            _serverInfo = new ServerInfo();
            initNetwork();
            Network.ConnectedChanged += OnConnected;
        }

        private void initNetwork()
        {
            Network.Register(0x01, "Compressed", null, true, null);
            Network.Register(0x02, "Login Response", 2, OnLoginResult);
            Network.Register(0x04, "Server Info", null, OnServerInfo);

        }
        /// <summary>
        /// Se connecte et se logue au server
        /// </summary>
        /// <param name="adress">Adresse ou IP du serveur</param>
        /// <param name="port">Port du serveur (2593 par defaut)</param>
        /// <param name="username">Nom d'utilisateur</param>
        /// <param name="password">Mot de passe du compte</param>
        /// <returns></returns>
        public bool Connect(string adress, int port, string username, string password)
        {
            _log.TraceFunction(adress, port, username, "******");
            Adress = adress;
            Port = port;
            Username = username;
            Password = password;
            return Network.Connect(adress, port);
        }

        public bool Connect(LoginInfo infos)
        {
            return Connect(infos.HostAdress, infos.Port, infos.Username, infos.Password);
        }

        private void OnConnected(object sender, EventArgs e)
        {
            
            Network.Send(new RemoteAdminLoginPacket(Username, Password));
            _requestInfoTimer = new System.Threading.Timer(RequestServerInfo, null, 0, 1000);
        }

        private void OnLoginResult(PacketReader reader)
        {
            LoginResponse response = (LoginResponse)reader.ReadByte();
            if (response == LoginResponse.OK)
                _requestInfoTimer = new System.Threading.Timer(RequestServerInfo, null, 0, 1000);
            else
                _requestInfoTimer = null;
            if (connected != null)
            {
                connected(this, response == LoginResponse.OK);
            }
        }

        private void RequestServerInfo(object dummy)
        {
            Network.Send(new ServerInfoRequestPacket());
        }

        private void OnServerInfo(PacketReader reader)
        {
            _serverInfo.Initialized = true;
            _serverInfo.ActiveAccountsCount = reader.ReadInt32();
            _serverInfo.BannedAccountsCount = reader.ReadInt32();
            _serverInfo.FirewalledIpCount = reader.ReadInt32();
            _serverInfo.OnlineCount = reader.ReadInt32();
            _serverInfo.MobileCount = reader.ReadInt32();
            _serverInfo.ScriptMobilesCount = reader.ReadInt32();
            _serverInfo.ItemsCount = reader.ReadInt32();
            _serverInfo.ScriptedItemsCount = reader.ReadInt32();
            _serverInfo.Uptime = TimeSpan.FromSeconds(reader.ReadUInt32());
            _serverInfo.MemoryUsage = reader.ReadUInt32();
            _serverInfo.TotalMemory = reader.ReadUInt32();
            _serverInfo.DotNetVersion = reader.ReadString();
            _serverInfo.OSVersion = reader.ReadString();
            if (UpdatedServerInfo != null)
                UpdatedServerInfo(this, EventArgs.Empty);
        }

        public void Disconnect()
        {
            if (this.connected != null)
                connected(this, false);
             Network.Disconnect();
        }
    }
}
